/**
 * 创建与月华交互的消息数组
 *
 * @param {string|undefined} promptMessage - 自定义提示消息，可选参数
 *
 * @returns {Promise<Array>} 包含role和content属性的消息对象数组
 */
async function createMessages(promptMessage) {
    /**
     * 对话历史数组
     */
    let messages = [];
    /**
     * 获取系统时间
     */
    const systemTime = `现在的时间是: (${getSystemTime()});`;
    /**
     * 系统提示内容
     */
    const content = inputSystemPrompt.value + `[ ${systemTime} ]`
    // 添加系统提示消息
    if (inputSystemPrompt.value.trim()) messages.push({ role: "system", content });
    /**
     * 加载对话历史消息
     */
    const history = await loadHistory();
    // 加载对话历史消息
    history.forEach(msg => messages.push({ role: msg.role, content: msg.content }))
    // 添加自定义提示消息
    if (promptMessage) messages.push({ role: "user", content: promptMessage });
    // 输出消息数组
    return messages;
};

/**
 * 加载对话历史消息
 */
async function loadHistory() {
    /**
     * 对话历史消息数组
     */
    let messages = [];
    /**
     * 计算对话历史总长度
     */
    const totalHistoryLength = conversationHistory.reduce((sum, msg) => sum + msg.content.length, 0);
    // 检查是否已连接到嵌入模型
    if (!isEmbeddingConnected) await embeddingEndpointConnection();
    /**
     * 使用向量数据库查询相关消息
     */
    const vectorMessages = await vectorQueryContext();
    // 合并向量数据库查询结果
    messages.push(...vectorMessages);
    // 判断是否为开发者模式
    if (isDeveloperMode) {
        /**
         * 序列化消息数组
         */
        const messagesJson = JSON.stringify(messages, null, 2);
        /**
         * 消息长度信息
         */
        const messagesLength = '历史对话字数:' + totalHistoryLength;
        /**
         * 消息格式的修饰符
         */
        const modify = ['<think>\n```json\n', '\n```\n</think>']
        /**
         * 渲染处理后的消息数组
         */
        const messageElement = tracelessRenderMessage(modify[0] + messagesJson + modify[1] + messagesLength, chatHistoryPanel);
        // 为think区块添加折叠功能
        messageElement?.querySelectorAll(".toggle_think_button").forEach(bindFoldingButton);
    };
    // 返回处理后的消息数组
    return messages;
};

/**
 * 创建助手消息元素并渲染到页面，为后续接收API响应做准备
 *
 * @param {HTMLElement} container - 消息容器元素，用于渲染助手消息
 *
 * @param {object} message - 助手消息内容
 *
 * @returns {Promise<HTMLElement>}  返回渲染到页面上的助手消息元素
 */
async function createMessageElement(container, message) {
    // 如果未连接到API，显示连接中状态并测试连接
    if (!isReasoningConnected) {
        // 显示连接中状态
        showSystemMessage("正在尝试连接API", "success");
        // 执行测试连接
        await reasoningEndpointConnection();
    };
    /**
     * 创建消息元素并将其渲染到页面上
     *
     * 这样用户可以看到助手已经开始准备回复
     */
    let messageElement = renderMessage(message, container);
    // 为消息元素创建停止按钮，允许用户中止当前的API请求
    if (messageElement) createStopButton(messageElement);
    // 禁用输入按钮，防止用户在请求处理期间重复发送消息，避免请求冲突
    disabledInputButton(true);
    // 创建中止控制器，用于后续在需要时取消正在进行的API请求
    abortController = new AbortController();
    // 设置月华为思考状态（无超时），提示用户月华正在处理请求
    setEmotionState(EmotionalState.THINKING);
    // 返回渲染到页面上的消息元素，供后续操作使用
    return messageElement;
};

/**
 * 获取用户输入的消息并清空输入框
 *
 * 从截图输入框、Live2D输入框和聊天输入框中获取内容，拼接后返回，同时清空这些输入框
 *
 * @returns {string} 拼接后的用户输入消息, 若消息长度超过最大长度, 则截取最大长度
 */
function getUserMessage() {
    /**
     * 将各输入框内容存储到数组中
     */
    const userInput = [screenshotInputBox, live2dInputBox, chatInputBox, renderInputBox, knowledgeInputBox];
    /**
     * 过滤掉空字符串
     */
    const message = userInput.map(item => item.value.trim()).filter(item => item).join('\n');
    // 清空所有输入框
    userInput.forEach(item => item.value = '');
    // 移除所有文本域的 style 属性
    document.querySelectorAll('.auto-resize-textarea').forEach(textarea => textarea.removeAttribute('style'));
    // 返回拼接后的消息
    return message.length >= messageSliceLength.value ? message.slice(0, messageSliceLength.value) : message;
};

/**
 * 批量启用或禁用输入按钮
 *
 * @param {boolean} disabled - 一个布尔值，用于指定是否禁用按钮。true 表示禁用，false 表示启用
 */
function disabledInputButton(disabled) {
    // 设置截图输入按钮的禁用状态
    screenshotInputButton.disabled = disabled;
    // 设置Live2D输入按钮的禁用状态
    live2dInputButton.disabled = disabled;
    // 设置聊天输入按钮的禁用状态
    chatInputButton.disabled = disabled;
};

/**
 * 获取所有输入按钮的禁用状态
 *
 * @returns {boolean} 如果所有按钮都被禁用则返回 true，否则返回 false
 */
function getInputButtonsDisabledState() {
    return (
        screenshotInputButton.disabled &&
        live2dInputButton.disabled &&
        chatInputButton.disabled
    );
};
